package tomcat.demo;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * NIO 服务端
 */
public class MyServer {
    public static void main(String[] args) throws Exception{
        serverSocketChannel();
    }

    // 通道管理器(Selector)
    private static Selector selector;
    private static ServerSocketChannel serverSocketChannel;
    private static int port = 8080;

    public static void serverSocketChannel() throws Exception{
        // 创建通道管理器(Selector)
        selector = Selector.open();

        // 获得一个ServerSocket通道
        serverSocketChannel = ServerSocketChannel.open();
        // 设置通道为非阻塞
        serverSocketChannel.configureBlocking(false);
        // 将该通道对于的serverSocket绑定到port端口，比如8080
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));

        /**
         * 将通道(Channel)注册到通道管理器(Selector)，并为该通道注册selectionKey.OP_ACCEPT事件
         * 注册该事件后，当事件到达的时候，selector.select()会返回，
         * 如果事件没有到达selector.select()会一直阻塞。
         */
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            // 当注册事件到达时，方法返回，否则该方法会一直阻塞
            selector.select();

            // 获取监听事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                // 获取事件
                SelectionKey key = iterator.next();

                // 移除事件，避免重复处理
                iterator.remove();

                System.out.println("已接收到消息---" + key);

                if (key.isAcceptable()){
                    handleAccept();
                }else if (key.isReadable()){
                    handleRead(key);
                }
            }

        }

    }
    private static void handleAccept() throws Exception{
        SocketChannel socketChannel = serverSocketChannel.accept();

        socketChannel.configureBlocking(false);

        // 给通道设置读事件，客户端监听到读事件后，进行读取操作
        socketChannel.register(selector,SelectionKey.OP_READ);
    }

    private static void handleRead(SelectionKey key) throws Exception{
        SocketChannel socketChannel = (SocketChannel) key.channel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(2*1024);
        //接收信息
        socketChannel.read(byteBuffer);

        System.out.println("server端接收到的消息是：");
        System.out.println(new String(byteBuffer.array()));

        //响应结果
        StringBuffer httpResponse = new StringBuffer();
        httpResponse.append("HTTP/1.1 200 OK\n")
                .append("Content-Type: text/html;charset=utf-8\n")
                .append("\r\n")
                .append("我是serverSocketChannel 服务端");
        socketChannel.write(ByteBuffer.wrap(httpResponse.toString().getBytes()));
        socketChannel.close();
    }
}
